package cn.com.idmy.auth.oauth;

import cn.com.idmy.auth.Authenticator;
import cn.com.idmy.auth.context.Request;
import cn.com.idmy.auth.context.Response;
import cn.com.idmy.auth.exception.AuthException;
import cn.com.idmy.auth.jwt.JwtTokenManager;
import cn.com.idmy.auth.login.LoginManager;
import cn.com.idmy.auth.oauth.model.*;
import cn.com.idmy.auth.oauth.token.OauthTokenFactory;
import cn.hutool.core.convert.Convert;
import cn.com.idmy.base.util.Assert;
import cn.hutool.core.lang.Console;
import cn.hutool.core.lang.TypeReference;
import com.alibaba.fastjson2.JSONObject;
import lombok.Data;

import java.time.Instant;
import java.util.Map;

@Data
public class OauthJwtManager {
    protected final LoginManager loginManager;
    protected final JwtTokenManager jwtTokenManager;
    protected Authenticator<?, ?> authenticator;
    protected OauthConfig oauthConfig = new OauthConfig();
    protected OauthTokenFactory oauthTokenFactory;

    public OauthJwtManager(LoginManager loginManager) {
        this.loginManager = loginManager;
        this.jwtTokenManager = (JwtTokenManager) loginManager.getTokenManager();
    }

    private static void checkClient(ClientIn in) {
        String uri = in.getUri();
        String clientId = in.getClientId();
        String clientSecret = in.getClientSecret();
        Console.log(uri, clientId, clientSecret);
    }

    public void init() {
        Assert.notNull(authenticator, "请设置认证器");
        Assert.notNull(oauthTokenFactory, "请设置认证器");
    }

    public Object authorize(Request request, Response response) {
        JSONObject params = request.getParams();
        AuthorizeIn in = params.toJavaObject(AuthorizeIn.class);

        String responseType = request.getParam(OauthConsts.RESPONSE_TYPE);
        if (ResponseType.CODE.getValue().equals(responseType)) {
            AuthorizationCode code = createCode(in);
            String redirectUri = OauthJwtUtil.buildRedirectUri(in.getRedirectUri(), code.getCode());
            return response.redirect(redirectUri);
        } else if (ResponseType.TOKEN.getValue().equals(responseType)) {
            throw new AuthException("不支持隐藏式");
        } else {
            throw new AuthException("无效 response_type: " + responseType);
        }
    }

    public AccessTokenOut token(Request request) {
        String grantType = request.getParam(OauthConsts.GRANT_TYPE);
        return oauthTokenFactory.get(grantType).getToken(request);
    }

    public AccessTokenOut createAccessToken(Object id, ClientIn in) {
        long now = Instant.now().getEpochSecond();
        long rtTimeout = now + oauthConfig.getRefreshTimeout();
        String refreshToken = JwtTokenUtil.of(id, null, oauthConfig.getRefreshAlgorithm(), rtTimeout);
        return AccessTokenOut.builder()
                .clientId(in.getClientId())
                .exp(now + jwtTokenManager.getGlobalConfig().getTimeout())
                .accessToken(jwtTokenManager.getToken())
                .refreshToken(refreshToken)
                .refreshExp(rtTimeout)
                ;
    }

    public AuthorizationCode createCode(AuthorizeIn authorizeIn) {
        Map<String, Object> map = Convert.convert(new TypeReference<>() {
        }, authorizeIn);
        return AuthorizationCode.builder()
                .clientId(authorizeIn.getClientId())
                .scope(authorizeIn.getScope())
                .redirectUri(authorizeIn.getRedirectUri())
                ;
    }

    public AuthorizationCode getCode(String jwtCode) {
        return AuthorizationCode.builder();
    }
}
